// MyTestSuite.h
#include <cxxtest/TestSuite.h>
#include "Matrix.h"
#include <string>
#include <sstream>

class MyTestSuite : public CxxTest::TestSuite 
{
public:
	
	bool testEqual(Matrix::Matrix& m1, Matrix& m2) {
		std::stringstream t1,t2;
		t1 << m1;
		t2 << m2;
		return (t1.str().compare(t2.str())==0);
	}
	
	void testAccess( void )
	{
		Matrix m(3,3);
		
		//Test valid access
		TS_ASSERT_THROWS_NOTHING(m[0][0] = -5);
		TS_ASSERT_THROWS_NOTHING(m[2][2] = 4);
		TS_ASSERT_EQUALS( m[0][0], -5 );
		TS_ASSERT_EQUALS( m[2][2], 4 );
		
		//Test off-by-one faults
		TS_ASSERT_THROWS_ANYTHING(m[3][4] = 6);
		TS_ASSERT_THROWS_ANYTHING(m[4][3] = 6);
	}
	
	void testOutput( void )
	{
		Matrix m(2,3);
		std::stringstream test;
		std::string teststr;
		std::string realstr = "[ 0 0 0 \n; 0 0 0 ]";
		test << m;
		teststr = test.str();
		TS_ASSERT( teststr.compare(realstr) == 0 );
	}
	
	void testInput( void )
	{
		Matrix m;
		
		std::stringstream intest;
		intest.str("[ 1 2 3 ; 4 5 6 ]");
		intest >> m;
		
		std::stringstream test;
		std::string teststr;
		std::string realstr = "[ 1 2 3 \n; 4 5 6 ]";
		test << m;
		teststr = test.str();
		TS_ASSERT( teststr.compare(realstr) == 0 );
	}
	
	void testNegativeInput( void )
	{
		Matrix m;
		
		std::stringstream intest;
		intest.str("[ -1 2 -3 ; -4 -5 6 ]");
		intest >> m;
		
		std::stringstream test;
		std::string teststr;
		std::string realstr = "[ -1 2 -3 \n; -4 -5 6 ]";
		test << m;
		teststr = test.str();
		TS_ASSERT( teststr.compare(realstr) == 0 );
	}
	
	void testAddition( void )
	{
		Matrix m(2),n(2),k;
		TS_ASSERT_THROWS_NOTHING
		(
		 m[0][0] = 3;
		 m[1][1] = 4;
		 n[0][0] = 3;
		 n[1][1] = 4;
		 k = m + n
		 );
		TS_ASSERT_EQUALS( k[0][0], 6 );
		TS_ASSERT_EQUALS( k[0][1], 0 );
		TS_ASSERT_EQUALS( k[1][0], 0 );
		TS_ASSERT_EQUALS( k[1][1], 8 );
		
	}
	
	void testMultiplicationScalar( void )
	{
		Matrix m(2),n(2),k;
		TS_ASSERT_THROWS_NOTHING
		(
		 m[0][0] = 3;
		 m[1][1] = 4;
		 n[0][0] = 3;
		 n[1][1] = 4;
		 k = m * 3
		 );
		TS_ASSERT_EQUALS( k[0][0], 9 );
		TS_ASSERT_EQUALS( k[0][1], 0 );
		TS_ASSERT_EQUALS( k[1][0], 0 );
		TS_ASSERT_EQUALS( k[1][1], 12 );
	}
	
	void testScalarMultiplication( void )
	{
		Matrix m(2),n(2),k;
		TS_ASSERT_THROWS_NOTHING
		(
		 m[0][0] = 3;
		 m[1][1] = 4;
		 n[0][0] = 3;
		 n[1][1] = 4;
		 k = 3 * m;
		 );
		TS_ASSERT_EQUALS( k[0][0], 9 );
		TS_ASSERT_EQUALS( k[0][1], 0 );
		TS_ASSERT_EQUALS( k[1][0], 0 );
		TS_ASSERT_EQUALS( k[1][1], 12 );
	}
	
	void testMultiplicationSquare(void)
	{
		Matrix m(2),n(2),k;
		m[0][0] = 3;
		m[1][1] = 4;
		m[0][1] = 5;
		n[0][0] = 11;
		n[1][1] = 13;
		n[1][0] = 12;
		
		TS_ASSERT_THROWS_NOTHING(k =  n*m);
		
		Matrix realans = Matrix(2);
		std::stringstream intest;
		intest.str("[ 33 55 ; 36 112 ]");
		intest >> realans;
		//TODO funkar inte för det finns ingen == operator, samma nedan
		TS_ASSERT(testEqual( k, realans ));
	}
	void testMultiplicationNotSquare(void)
	{	
		std::stringstream intest;
		
		Matrix a(1,4), b(4,2);
		
		intest.str("[ 4 2 0 3 ]");
		intest >> a;
		
		intest.str("[ 3 7 ; 0 0 ; 1 2 ; 0 8 ]");
		intest >> b;
		
		Matrix corr_ans(1,2);
		intest.str("[ 12 52 ]");
		intest >> corr_ans;
		TS_ASSERT_THROWS_ANYTHING(b*a)
		Matrix c = a*b;
		TS_ASSERT(testEqual( c, corr_ans ));
	}
	
	
	void testZeroMatrix( void )
	{
		Matrix m,n(0),k(0,0);
		TS_ASSERT_THROWS_NOTHING(m*n);
		Matrix c = 3*m;
		TS_ASSERT(testEqual(c,k));
		c = 3*m;
		TS_ASSERT(testEqual(c, m));
		c = m+n;
		TS_ASSERT(testEqual(c,k));
		TS_ASSERT(testEqual(m,n));
		TS_ASSERT(testEqual(m,k));
		c = m.transpose();
		TS_ASSERT(testEqual(m,c));
	}
	
	void testTranspose( void )
	{
		std::stringstream intest;
		
		Matrix a(1,4), b(4,2);
		
		intest.str("[ 3 0 1 0 ; 7 0 2 8 ]");
		intest >> a;
		
		intest.str("[ 3 7 ; 0 0 ; 1 2 ; 0 8 ]"); 
		intest >> b;
		
		Matrix tb = b.transpose();
		Matrix ta = a.transpose();
		
		TS_ASSERT(testEqual(tb, a));
		TS_ASSERT(testEqual(ta, b));
	}
	
	void testNegation( void )
	{
		std::stringstream intest;
		
		Matrix a,b;
		
		intest.str("[ 3 0 1 0 ; 7 0 2 8 ]");
		intest >> a;
		
		intest.str("[ -3 0 -1 0 ; -7 0 -2 -8 ]");
		intest >> b;
		
		Matrix c = -a;
		TS_ASSERT(testEqual(c , b));
	}
	
};
